#ifndef INSTANCES_H
#define INSTANCES_H
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include "instance.h"
#include "select_attrs.h"
#include "attr_ave.h"

using namespace std;

//====================================================
// Class: instances
//        the class stands for the data set we'll use,
//        for example: training set,test set,classify set.
//Author: Junix<unix_jun@yahoo.com.cn>
//Date:   2007-11-16
//====================================================


//used as function pointer for_each of STL.
bool miss_instance (instance & ins)
{
    return ins.missing ();
}

class instances
{
public:
//====================================================
// Constructor and Deconstructor
//====================================================
    instances ()
    {
        _instances = new vector < instance >;
        _attr_infos = NULL;
    }

    //由数据文件读入。构成所有的Instances集合。
    instances (string file, vector < int >sel, vector < attribute_info > *infos)
    {
        _attr_infos = infos;
        _instances = new vector < instance >;
        copy (sel.begin (), sel.end (), back_inserter (_bitmap));
        ifstream data_set (file.c_str ());
        string tuple;

        while (getline (data_set, tuple))
        {
            instance ins (tuple, sel, infos);
            _instances->push_back (ins);
        }
        //this make the _ave have the same structure as the normal instance.
        _ave = _instances->front();

    }

    //删除_instance.
    ~instances ()
    {
        _instances->clear ();
        delete _instances;
    }

    //data clean both learning and testing step
    int data_clean ()
    {
        calculate_ave ();
        fix_missing ();
        return 0;
    }

//==============================================================
//  Some Utils For The Class
//==============================================================
    int calculate_ave ()
    {
        vector<attr_ave> ave;
        //Init
        for (int i=0;i<_bitmap.size();i++)
        {
            attr_ave nattr_ave(_bitmap.at(i),_attr_infos);
            ave.push_back(nattr_ave);
        }
        //first scan for count unmissing attributions
        for (int i = 0; i < _instances->size (); i++)
        {
            instance ins = _instances->at(i);
            for (int j = 0; j < ins._attrs.size (); j++)
            {
                if (ins._attrs.at (j).type () == ATTR_NUMERIC)
                {
                    if (!ins._attrs.at (j)._missing)
                        ave.at (j)._count++;
                }
            }
        }

        //second time scan
        for (int i = 0; i < _instances->size (); i++)
        {
            instance ins = _instances->at(i);
            for (int j = 0; j < ins._attrs.size (); j++)
            {
                if (ins._attrs.at (j).type () == ATTR_DISCRETE)
                {
                    if (!ins._attrs.at (j)._missing)
                    {
                        string item = ins._attrs.at (j).discrete ();
                        ave.at (j)._discrete_attr_map[item]++;
                    }
                }
                else//ATTR_NUMERIC
                {
                    if (!ins._attrs.at (j)._missing)
                    {
                        float numeric = ins._attrs.at (j).numeric ();
                        float delt = numeric / ave.at(j)._count;
                        ave.at (j)._mean += delt;
                    }
                }
            }
        }
        //Now get the average attr
        for (int i=0;i<_ave._attrs.size();i++)//for every attr
        {
            if (ave.at(i)._type==ATTR_DISCRETE)
            {
                int count=0;
                string item="";
                map<string,int>::iterator iter=	ave.at(i)._discrete_attr_map.begin();
                while (iter!=ave.at(i)._discrete_attr_map.end())
                {
                    if (iter->second >= count)
                    {
                        count=iter->second;
                        item=iter->first;
                    }
                    iter++;
                }
                _ave._attrs.at(i).discrete(item);
                _ave._attrs.at(i).missing(false);
            }
            else
            {
                _ave._attrs.at(i).numeric(ave.at(i)._mean);
                _ave._attrs.at(i).missing(false);
            }
        }
    }

    //fix the missing value attribution.
    int fix_missing ()		//for test step
    {
        vector < instance >::iterator iter = _instances->begin ();
        while (iter != _instances->end ())
        {
            iter->fix_missing (_ave);
            iter++;
        }
        return 0;
    }

    //for learning step by Naive Bayes.
    void ignore_missing ()
    {
        vector<instance> *_instances2 = new vector<instance>;
        remove_copy_if(_instances->begin (), _instances->end (),back_inserter( *_instances2), miss_instance);
        _instances->clear();
        delete _instances;
        _instances = _instances2;
    }

//=============================================================
//     print for debug
//=============================================================
    void print ()
    {
        copy(_instances->begin(),_instances->end(),ostream_iterator<instance>(cout));
    }

    friend ostream& operator<<(ostream& os,instances& inss)
    {
        copy(inss._instances->begin(),inss._instances->end(),ostream_iterator<instance>(os));
        return os;
    }

    int size ()
    {
        return _instances->size ();
    }
    //
    attribute_info& label_attr_info()
    {
        return _attr_infos->back();
    }

//=============================================================
//member
//=============================================================
    vector < int >   _bitmap;
    instance _ave;		//Used to fix missing value.
    vector < instance > *_instances;
    vector < attribute_info > *_attr_infos;
};

#endif
